package com.yifushidai.utils;

import com.yifushidai.entity.IdcardEntity;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;

/**
 * 千景多功能身份证读卡器串口通讯协议.pdf
 */
public class QianjingPackUtils {

    private static final byte[] QSZ_BYTES = new byte[]{(byte) 0xFA, (byte) 0xFB, (byte) 0xFC, (byte) 0xFD};//起始帧 4字节 FA FB FC FD
    private static final byte[] SFZ_CDY_BYTES = new byte[]{(byte) 0x04, (byte) 0x05};//长度域(除起始帧和结束帧的长度) 2字节 0000-FFFF 0x0504=1284
    private static final byte[] MAC_CDY_BYTES = new byte[]{(byte) 0x0E, (byte) 0x00};//长度域(除起始帧和结束帧的长度) 2字节 0000-FFFF 0x000E=14
    private static final byte[] ZTY_BYTES = new byte[]{(byte) 0x00};//状态域 1字节 成功:0 失败:非 0

    private static final int HEAD_OFFSET2 = 7;
    private static final int QSZ_OFFSET = 4;
    private static final int CDY_OFFSET = 2;
    private static final int ZTY_OFFSET = 1;

    private static final int MAC_OFFSET = 8;
    private static final int XM_OFFSET = 30;
    private static final int XB_OFFSET = 2;
    private static final int MZ_OFFSET = 4;
    private static final int CS_OFFSET = 16;
    private static final int ZZ_OFFSET = 70;
    private static final int GMSFZHM_OFFSET = 36;
    private static final int QFJG_OFFSET = 30;
    private static final int YXQSRQ_OFFSET = 16;
    private static final int YXJZRQ_OFFSET = 16;
    private static final int BY_OFFSET = 36;
    private static final int ZPXX_OFFSET = 1024;

    private static final int ZPBMP_LENGTH = 38556;
    private static final int SFZINFO_PACKAGE_LENGTH = 1289;//1280+9
    private static final int SFZUID_PACKAGE_LENGTH = 19;//10+9

    public static void main(String[] args) throws IOException {
        byte[] payloadBytes = HexUtils.hexStringToBytes("FAFBFCFD040500554F00659B6D200020002000200020002000200020002000200020002000310030003100310039003900330031003100300034007F89895B025E6854F381BF53CC5BC14E614ECC5BC14E51672D4EC35F5788320038003900F75320002000200020002000200020002000200020002000200020002000200020003600310030003100320034003100390039003300310031003000340034003500310032006854F381BF536C51895B405C2000200020002000200020002000200020003200300031003000300037003200300032003000320030003000370032003000200020002000200020002000200020002000200020002000200020002000200020002000574C66007E00320000FF85195151513E710DD564F304D1AF7837A655E2D9D5D039AE512A35396D633061CA6FD11B620AD6D143E77CFD073F90F43343F7CB25A728897237F1D6A7D6EFFC9FFC45E9731E64B31A247951AEDA5251515A3E81ABD91546249D3BEE16E4CC70F62B028103A13D60B0F976C02D2A0F19BD5D79792C284FED356582CD8C157490DFD9488BEB0724A90B8A2450EECC2C940586F9A4A5745E76666A454838D0DB0EFE4DC7FE7AF98C26FAF4735EC4E47C5BC63E11B87C7E4D6AA4089A6362C0654900DBFCDAAC2FA4A9B547B4B4953946B17C78F3AA18D87B271A1E07E4C45673E0FD3051FA90E508849D23860A69065010F6B7211EEF976710FE1729B10DC7A43D0997CBEF45F0EF6D938A1CFF452A38FE96E8E7859A29F64FF0E425267E631875A2B661EF9887E243310059A495ED1173FBF01C4D6FD1846A136390E140B12900F91E30E784D1C19863E1F75932BB16296F7D512EDD71793F80647313769BAA8868B5BE6F97993F794F6FF518C4C549205E9647AE51B6EB25115E5030AB6EB5C9E598FC5EE4479DDD886823C35C18914C48CB53FBF24B4A892123AE5148F44E48D4FD8AA6EBAADB11BCE9722D5114700796340B7DF687BC3A174ACE3CBFC38E9C9BC82C1DC672A62487D9CA30EC16AA73C6A20C6729B8BD6EDDFC6FF1277F93BED3723420FC19DE83F1B8710F7E04288C8CA791F10CB7AE51ED769F5C69C2DFEB0F4564CC285CCBBFAB751523052FA275F9E0241CA2526DBD80CF4C5E330EBFD35E9E8C0DEFAE51D1C7181128BAF9B47471BE40A82314E420E54F57FA57959017D6A218564887A01940C80DBC29F3F18D5914A482CE3B30EB1B2A95B4B3A9E7EDA242F83446F6BD2A577A5721A977970DDB3FF368CCAE5125C3739B690C8A18E198BC25942C890A9937D6530D168D78E5AB3D58375A7AE0475D7D514FA1D7561277559EDC9E9C695544B9C42EE148D12659F95C3014654645DD3D2C977C8876ED761BBC0C2CB83C3048D39B4243CC6647BEF3232A468C6FB6FEF165805D6C4413E29417C1A4BE3B9DF4731DAF0583C1ABF4D116FC8E41351DAD40BCFD1360BF4849F61AB51D1E6A024C267B3112121CFF3F5069B03A3E499665146B44C013F58F42067A7B4EF908F01C6EC3974BD73BB3913A5D4936DB4CEF02AD33EC012FE905E77DCD31DFEBD87D426C23C98B2C6364173D6C392F01E81F24935A3E31116277AA985C9DE4293A31C9CAA1665E25370CA11022EAD0DCE213FCC5FC2C377AF12778415115DE67CB78BA10D153E435BF6949106BE08F261CF39A593972F4CA4CCC3C1005E5432026A51A00EDBC5A3E8B62462328828F2544A6E0D75158872A28D1A242A44A2DFAA42F2B773CDB5DCF4130F2B042DF88839FA980E5BCC3E970CD0247BE1B2EDA442156FA3DBCDB27D1E701CC3A419C7144F4BBFAFBFCFD0E00003125C602C00512A8900031BB");
        unpack(payloadBytes);

    }

    /**
     * 数据解包
     *
     * @param payloadBytes 有效载荷含2个子包：身份证信息包（前1289字节）、身份证UID包（后19字节）
     * @return 有效载荷(PAYLOAD)
     */
    public static IdcardEntity unpack(byte[] payloadBytes) {
        byte[] sfzPackage = new byte[SFZINFO_PACKAGE_LENGTH];
        byte[] uidPackage = new byte[SFZUID_PACKAGE_LENGTH];
        System.arraycopy(payloadBytes, 0, sfzPackage, 0, SFZINFO_PACKAGE_LENGTH);
        System.arraycopy(payloadBytes, SFZINFO_PACKAGE_LENGTH, uidPackage, 0, SFZUID_PACKAGE_LENGTH);

        //子包 异或位校验
        byte sfzXor = sfzPackage[SFZINFO_PACKAGE_LENGTH - 2];
        byte[] sfzXorPackage = new byte[SFZINFO_PACKAGE_LENGTH - 6];
        System.arraycopy(sfzPackage, QSZ_OFFSET, sfzXorPackage, 0, SFZINFO_PACKAGE_LENGTH - 6);
//        System.out.println(sfzXor);
//        System.out.println(generateXorByte(sfzXorPackage));
        if (sfzXor != generateXorByte(sfzXorPackage)) return null;
        byte uidXor = uidPackage[SFZUID_PACKAGE_LENGTH - 2];
        byte[] uidXorPackage = new byte[SFZUID_PACKAGE_LENGTH - 6];
        System.arraycopy(uidPackage, QSZ_OFFSET, uidXorPackage, 0, SFZUID_PACKAGE_LENGTH - 6);
//        System.out.println(uidXor);
//        System.out.println(generateXorByte(uidXorPackage));
        if (uidXor != generateXorByte(uidXorPackage)) return null;

        /*
        子包一、身份证信息包（前1289字节）：
         */
        //一、头文件不用理会：7 个字节
        //二 、256字节 文字信息：1 个汉字 = 2 个字节 = 4 个字符
        byte[] xmBytes = new byte[XM_OFFSET];//1、30 字节姓名
        byte[] xbBytes = new byte[XB_OFFSET];//2、2 字节性别
        byte[] mzBytes = new byte[MZ_OFFSET];//3、4 字节名族
        byte[] csBytes = new byte[CS_OFFSET];//4、16 字节出生
        byte[] zzBytes = new byte[ZZ_OFFSET];//5、70 字节住址
        byte[] gmsfzhmBytes = new byte[GMSFZHM_OFFSET];//6、36 字节公民身份证号码
        byte[] qfjgBytes = new byte[QFJG_OFFSET];//7、30 字节签发机关
        byte[] yxqsrqBytes = new byte[YXQSRQ_OFFSET];//8、16 字节有效期起始日期
        byte[] yxjzrqBytes = new byte[YXJZRQ_OFFSET];//9、16 字节有效期截止日期
        byte[] byBytes = new byte[BY_OFFSET];//10、36 字节备用
        //三、1024字节 照片信息：
        //1、1024 字节相片数据为原始加密数据，Linux 和单片机无法解析，目前只有Windows 和 Android 相片解码库。
        //2、依据相片解码库，传入原始数据可以获得相片的.bmp 原始数据（可以保存另存为.jpg 或者.bmp 相片）。
        //3、可以根据自身需求，再次转换成 Base64 相片数据。
        byte[] zpxxBytes = new byte[ZPXX_OFFSET];//解码前文件wlt数据存放地址,1024字节
        byte[] zpbmpBytes = new byte[ZPBMP_LENGTH];//解码后图像原始数据存放地址, 38556（102×126×3）字节，可根据需求生成BMP或者JPG，图像数据BGR格式，需要将B、R值互换。

        System.arraycopy(sfzPackage, HEAD_OFFSET2, xmBytes, 0, XM_OFFSET);
        System.arraycopy(sfzPackage, HEAD_OFFSET2 + XM_OFFSET, xbBytes, 0, XB_OFFSET);
        System.arraycopy(sfzPackage, HEAD_OFFSET2 + XM_OFFSET + XB_OFFSET, mzBytes, 0, MZ_OFFSET);
        System.arraycopy(sfzPackage, HEAD_OFFSET2 + XM_OFFSET + XB_OFFSET + MZ_OFFSET, csBytes, 0, CS_OFFSET);
        System.arraycopy(sfzPackage, HEAD_OFFSET2 + XM_OFFSET + XB_OFFSET + MZ_OFFSET + CS_OFFSET, zzBytes, 0, ZZ_OFFSET);
        System.arraycopy(sfzPackage, HEAD_OFFSET2 + XM_OFFSET + XB_OFFSET + MZ_OFFSET + CS_OFFSET + ZZ_OFFSET, gmsfzhmBytes, 0, GMSFZHM_OFFSET);
        System.arraycopy(sfzPackage, HEAD_OFFSET2 + XM_OFFSET + XB_OFFSET + MZ_OFFSET + CS_OFFSET + ZZ_OFFSET + GMSFZHM_OFFSET, qfjgBytes, 0, QFJG_OFFSET);
        System.arraycopy(sfzPackage, HEAD_OFFSET2 + XM_OFFSET + XB_OFFSET + MZ_OFFSET + CS_OFFSET + ZZ_OFFSET + GMSFZHM_OFFSET + QFJG_OFFSET, yxqsrqBytes, 0, YXQSRQ_OFFSET);
        System.arraycopy(sfzPackage, HEAD_OFFSET2 + XM_OFFSET + XB_OFFSET + MZ_OFFSET + CS_OFFSET + ZZ_OFFSET + GMSFZHM_OFFSET + QFJG_OFFSET + YXQSRQ_OFFSET, yxjzrqBytes, 0, YXJZRQ_OFFSET);
        System.arraycopy(sfzPackage, HEAD_OFFSET2 + XM_OFFSET + XB_OFFSET + MZ_OFFSET + CS_OFFSET + ZZ_OFFSET + GMSFZHM_OFFSET + QFJG_OFFSET + YXQSRQ_OFFSET + YXJZRQ_OFFSET, byBytes, 0, BY_OFFSET);
        System.arraycopy(sfzPackage, HEAD_OFFSET2 + XM_OFFSET + XB_OFFSET + MZ_OFFSET + CS_OFFSET + ZZ_OFFSET + GMSFZHM_OFFSET + QFJG_OFFSET + YXQSRQ_OFFSET + YXJZRQ_OFFSET + BY_OFFSET, zpxxBytes, 0, ZPXX_OFFSET);
//        System.out.println(HexUtils.hexByes2String(HexUtils.hexBytesH2L(xmBytes), "UTF-16BE"));

        IdcardEntity idcardEntity = new IdcardEntity();
        idcardEntity.setXm(HexUtils.decodeUTF16LE(xmBytes).trim());
        idcardEntity.setXb(HexUtils.decodeUTF16LE(xbBytes).trim());
        idcardEntity.setMz(HexUtils.decodeUTF16LE(mzBytes).trim());
        idcardEntity.setCs(HexUtils.decodeUTF16LE(csBytes).trim());
        idcardEntity.setZz(HexUtils.decodeUTF16LE(zzBytes).trim());
        idcardEntity.setGmsfzhm(HexUtils.decodeUTF16LE(gmsfzhmBytes).trim());
        idcardEntity.setQfjg(HexUtils.decodeUTF16LE(qfjgBytes).trim());
        idcardEntity.setYxqsrq(HexUtils.decodeUTF16LE(yxqsrqBytes).trim());
        idcardEntity.setYxjzrq(HexUtils.decodeUTF16LE(yxjzrqBytes).trim());
        idcardEntity.setBeiyong(HexUtils.decodeUTF16LE(byBytes).trim());

        //中文解析乱码
        if (!HexUtils.decodeUTF16LE(yxqsrqBytes).trim().matches("^\\d{8}$")
                || !HexUtils.decodeUTF16LE(yxjzrqBytes).trim().matches("^\\d{8}$"))
            return null;

        //照片处理
        int result = 0;
        try {
//            result = GetSFZPic.CLibrary.wltToBmp.unpack(zpxxBytes, zpbmpBytes, 1);//调用DLL 解析BMP照片（windows 32位jdk）
            System.out.println("bmp:" + result);
            if (result == 1) {
                File srcFile = new File(System.getProperty("user.dir") + File.separator + "zp.bmp");
                String bmpFile = HexUtils.decodeUTF16LE(gmsfzhmBytes).trim() + ".bmp";
                File dstFile = new File(System.getProperty("user.dir") + "/src/main/webapp/sfz/" + bmpFile);
                FileUtils.copyFile(srcFile, dstFile);
                idcardEntity.setBmpUrl("localhost:8082/sfz/" + bmpFile);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        /*
        子包二、身份证UID包（后19字节）：
         */
        byte[] uidBytes = new byte[MAC_OFFSET];//8 字节mac
        System.arraycopy(uidPackage, HEAD_OFFSET2, uidBytes, 0, MAC_OFFSET);
        idcardEntity.setUid(HexUtils.bytesToHexString(uidBytes));

//        System.out.println("数据解包:" + JSON.toJSONString(idcardEntity));

        return idcardEntity;
    }

    private static byte generateXorByte(byte[] xorPackage) {
        byte xorByte = xorPackage[0];
        for (int i = 1; i < xorPackage.length; i++) {
            xorByte ^= xorPackage[i];
        }
        return xorByte;
    }

}
